package com.demo.auth.config;

import com.demo.auth.filter.ValidateCodeFilter;
import com.demo.auth.properties.SecurityProperties;
import com.demo.auth.handler.AuthenticationFailureHandlerImpl;
import com.demo.auth.handler.AuthenticationSuccessHandlerImpl;
import com.demo.auth.session.MyExpiredSessionStrategy;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * WEB 认证相关配置
 *
 * @author YT
 * @date 2019-05-23
 */
@Primary
@Order(90)
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private AuthenticationSuccessHandlerImpl authenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandlerImpl authenticationFailureHandler;

    @Autowired
    private ValidateCodeFilter validateCodeFilter;

    @Autowired
    private SmsCodeSecurityConfig smsCodeSecurityConfig;

    /**
     * 对所有 Http 的请求进行认证
     *
     * @param http
     */
    @Override
    @SneakyThrows
    protected void configure(HttpSecurity http) {
        http
                .apply(smsCodeSecurityConfig)
                .and()
                // 配置自定义登录成功处理器过滤器在 UsernamePasswordFilter 之前执行
                .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .formLogin()
                // 默认请求
                .loginPage("/login")
                // 自定义登录表单提交地址,配置后让 UserDetaileService 可以识别,并进行身份校验
                .loginProcessingUrl("/auth/login")
                // 配置验证码在
                .successHandler(authenticationSuccessHandler)
                // 配置自定义登录失败处理器
                .failureHandler(authenticationFailureHandler)
//        http.httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers("/login",
                        "/code/image",
                        "/sms/**",
                        "/session/invalid",
                        securityProperties.getBrowser().getLoginPage()).permitAll()
                .anyRequest()
                .authenticated()
                // 存在cookie，并限定过期时间
                .and()
                .rememberMe().tokenValiditySeconds(2419200)
                .and()
                .sessionManagement().invalidSessionUrl("/session/invalid")
                // 设置同一个用户最大的 session 数量
                .maximumSessions(1)
                // 设置当用一个用户登录后, 后面登录同样的用户就不能登录
                .maxSessionsPreventsLogin(true)
                .expiredSessionStrategy(new MyExpiredSessionStrategy())
                .and()
                .and()
                .logout().logoutSuccessUrl("/login")
                // 禁用 CSRF 防护功能
                .and()
                .csrf().disable();

    }

    /**
     * spring security 密码加密
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}
